///////////////////////////////////////////////////////////////////////////////
// File:        Player.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include "common/player/Player.hpp"
using namespace monkey::common::player;

///////////////////////////////////////////////////////////////////////////////

Player::Player(int id)
    : id_(id)
    , writebuffs_()
{

}

Player::~Player(void)
{

}

///////////////////////////////////////////////////////////////////////////////

void Player::Send(const char* data, size_t length)
{
    assert(data);
    if (writebuffs_.empty() && !this->WritePending())
    {
        int ret = this->Write(data, length);
        if (ret != SOCKET_ERROR)
        {
            int remain = 0;
            if (ret == SOCKET_ERROR_WOULDBLOCK)
            {
                remain = length;
                ret = 0;
            }
            else
                remain = length - ret;

            if (ret != length)
            {
                if (!SendPending(data + ret, remain))
                {
                    this->Close();
                }
            }

            return;
        }

        this->Close();
    }
    else
    {
        if (!SendPending(data, length))
        {
            this->Close();
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

bool Player::OnRead(void)
{
    return Parent::OnRead();
}

bool Player::OnWrite(void)
{
    Parent::OnWrite();

    if (writebuffs_.size() <= 0)
        return true;

    WriteBuffer* buf = writebuffs_[0];
    if (!buf->Send(this))
        return false;

    if (buf->Empty())
    {
        writebuffs_.pop_front();
        delete buf;
    }

    return true;
}

void Player::OnClose(void)
{
    while (!writebuffs_.empty())
    {
        WriteBuffer* buf = writebuffs_[0];

        writebuffs_.pop_front();
        delete buf;
    }

    Parent::OnClose();
}

///////////////////////////////////////////////////////////////////////////////

bool Player::SendPending(const char* data, size_t length)
{
    assert(data && length > 0);
    WriteBuffer* buf = new WriteBuffer();
    if (buf)
    {
        if (buf->Fill(data, length))
        {
            writebuffs_.push_back(buf);
            return true;
        }
        delete buf;
    }
    return false;
}